//------------------------------------------------------------------------------
// <copyright file="Item.cs" company="Damian Antonowicz">
//       copyright © 2010 Damian Antonowicz
// </copyright>
// <author>Damian Antonowicz</author>
// <email>poczta@damianantonowicz.pl</email>
//------------------------------------------------------------------------------

using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Xml.Serialization;
using DAnton.Utilities.Extensions;

namespace DotBeer.Business.Entities
{
    /// <summary>
    /// Contains informations about specified item.
    /// </summary>
    public class Item : AbstractItem, ICloneable
    {
        #region private properties

        bool replacementSpecified,
             additionalItemsAmountSpecified,
             additionalItemsSpecified;

        string url,
               vendor;

        int position,
            cost,
            recipceCost,
            additionalItemsAmount;

        ItemsCollection itemsCollection;

        ObservableCollection<ItemHero> createdWithItems = new ObservableCollection<ItemHero>();
        ObservableCollection<ItemHero> additionalItems = new ObservableCollection<ItemHero>();

        #endregion

        #region public properties

        public override string Name
        {
            get { return name; }
            set
            {
                name = value;
                OnPropertyChanged("Name");
                OnPropertyChanged("ImagePath");
            }
        }

        public override int TotalCost
        {
            get { return GetTotalCost(); }
        }

        public override int Cost
        {
            get { return this.cost; }
            set
            {
                this.cost = value;
                OnPropertyChanged("Cost");
                OnPropertyChanged("TotalCost");
            }
        }

        public override int RecipeCost
        {
            get { return this.recipceCost; }
            set
            {
                this.recipceCost = value;
                OnPropertyChanged("RecipeCost");
                OnPropertyChanged("TotalCost");
            }
        }

        public string Vendor
        {
            get { return this.vendor; }
            set
            {
                this.vendor = value;
                OnPropertyChanged("Vendor");
            }
        }

        public override string Url
        {
            get { return this.url; }
            set
            {
                this.url = value;
                OnPropertyChanged("Url");
            }
        }

        public int Position
        {
            get { return this.position; }
            set { this.position = value; }
        }

        [XmlIgnore]
        public bool ReplacementSpecified
        {
            get { return this.replacementSpecified; }
        }

        public ObservableCollection<ItemHero> CreatedWithItems
        {
            get { return this.createdWithItems; }
            set { this.createdWithItems = value; }
        }

        public int AdditionalItemsAmount
        {
            get { return this.additionalItemsAmount; }
            set
            {
                if ((int)value >= 1)
                {
                    this.additionalItemsAmount = value;
                    OnPropertyChanged("AdditionalItemsAmount");
                    OnPropertyChanged("TotalCost");
                }
            }
        }

        [XmlIgnore]
        public bool AdditionalItemsAmountSpecified
        {
            get { return this.additionalItemsAmountSpecified; }
        }

        public ObservableCollection<ItemHero> AdditionalItems
        {
            get { return this.additionalItems; }
            set { this.additionalItems = value; }
        }

        [XmlIgnore]
        public bool AdditionalItemsSpecified
        {
            get { return this.additionalItemsSpecified; }
        }

        [XmlIgnore]
        public ItemsCollection ItemsCollection
        {
            get { return this.itemsCollection; }
            set 
            { 
                this.itemsCollection = value;

                foreach (ItemHero itemHero in this.createdWithItems)
                    itemHero.ItemsCollection = this.itemsCollection;

                foreach (ItemHero itemHero in this.additionalItems)
                    itemHero.ItemsCollection = this.itemsCollection;
            }
        }

        #endregion

        #region constructors

        public Item()
        {
            recipeCostSpecified = true;
            this.costSpecified = true;
            this.urlSpecified = true;
            this.replacementSpecified = false;
            this.additionalItemsSpecified = false;
            this.additionalItemsAmountSpecified = false;

            this.createdWithItems.CollectionChanged += new NotifyCollectionChangedEventHandler(this.createdWithItems_CollectionChanged);
            this.additionalItems.CollectionChanged += new NotifyCollectionChangedEventHandler(this.additionalItems_CollectionChanged);
        }

        #endregion

        #region public methods

        #endregion

        #region private methods

        private int GetTotalCost()
        {
            int totalCost = this.cost + this.recipceCost;

            this.createdWithItems.ForEach(item => totalCost += item.TotalCost);

            if (this.additionalItems.Count > 0)
                totalCost += this.additionalItems[0].TotalCost * this.additionalItemsAmount;

            return totalCost;
        }

        void createdWithItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                OnPropertyChanged("TotalCost");

                ItemHero itemHero = this.createdWithItems[e.NewStartingIndex];
                itemHero.ItemsCollection = this.itemsCollection;
                itemHero.AmountSpecified = true;
                itemHero.PropertyChanged += new PropertyChangedEventHandler(Item_PropertyChanged);
            }
            else if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                OnPropertyChanged("TotalCost");
            }
        }

        void additionalItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                OnPropertyChanged("TotalCost");

                this.additionalItemsSpecified = true;
                this.additionalItemsAmountSpecified = true;

                this.additionalItems[e.NewStartingIndex].AmountSpecified = true;
            }
            else if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                OnPropertyChanged("TotalCost");

                if (this.additionalItems.Count == 0)
                {
                    this.additionalItemsSpecified = false;
                    this.additionalItemsAmountSpecified = false;
                }
            }
        }

        void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "TotalCost")
                OnPropertyChanged("TotalCost");
        }

        #region ICloneable Members

        public Item Clone()
        {
            Item item = new Item()
            {
                AdditionalItems = new ObservableCollection<ItemHero>(this.additionalItems.Clone()),
                AdditionalItemsAmount = this.additionalItemsAmount,
                Cost = this.cost,
                CreatedWithItems = new ObservableCollection<ItemHero>(this.createdWithItems.Clone()),
                Name = this.name,
                Position = this.position,
                RecipeCost = this.recipceCost,
                Url = this.url,
                Vendor = this.vendor
            };

            return item;
        }

        #endregion

        #region ICloneable Members

        object ICloneable.Clone()
        {
            return Clone();
        }

        #endregion

        #endregion
    }
}
